#ifndef  HELPER_OBJECT_ARRAY_H
#define  HELPER_OBJECT_ARRAY_H

#include <utility>
#include <memory>
#include "helper/object/Object.h"
#include "helper/object/Iterator.h"
#include "helper/object/RawType.h"

namespace helper {
namespace object {

class String;
class Hash;

/**
 *  abstract Array interface
 */
class Array : public Object{
public:
    /// value type of Array element (pointer)
    typedef Object * ValueType;

    Array() : Object(Object::ARRAY) {}
    /// free the memory of ValueType(Object *)
    ~Array() override {}


    /**
     * @return the length of array
     */
    virtual size_t size() const = 0;

    /**
     * <p> get the pointer of element in index (0-based)
     * @return ptr to value type (Object *) of array
     */
    virtual const ValueType * get(const int index) const = 0;
    const ValueType * operator[](const int index) const{
        return get(index);
    }
    virtual std::pair<bool, char> getByte(const int index) = 0;
    virtual std::pair<bool, int> getInt(const int index) = 0;
    virtual std::pair<bool, long long> getLongLong(const int index) = 0;
    virtual std::pair<bool, double> getDouble(const int index) = 0;

    virtual std::pair<bool, std::string> getStdString(const int index) = 0;

    virtual String * getString(const int index) = 0;
    virtual const String * getString(const int index) const = 0;
    virtual Array * getArray(const int index) = 0;
    virtual const Array * getArray(const int index) const = 0;
    virtual Hash * getHash(const int index) = 0;
    virtual const Hash * getHash(const int index) const = 0;

    virtual std::pair<bool, void *> getPointer(const int index) = 0;
    virtual int appendPointer(const void * ptr) = 0;

    virtual int append(char ch) = 0;
    virtual int append(int i) = 0;
    virtual int append(long long ll) = 0;
    virtual int append(double dbl) = 0;
    
    virtual int append(const char * str) = 0;
    virtual int append(const char * buffer, size_t len) = 0;
    virtual int append(const char * buffer, size_t offset, size_t len) = 0;
    virtual int append(size_t n, const char ch) = 0;
    virtual int append(const std::string & str) = 0;

    /**
     * @param o append the value ptr to array
     */
    virtual int append(const ValueType &o) = 0;

    /** 
     *
     * the memory of old value is managed by user
     * <pre>{@code
     *      Object * old = this.remove(0);
     *      delete old;
     * }</pre>
     *
     * <p> just remove the value(Objet *) in the private container
     * @param index the index of element in array
     */
    virtual ValueType remove(const int index) = 0;

    /**
     * <p> set the value to index in the container
     * nothing to do for old value 
     *
     *<pre>{@code
     *      Object * new = new Object();
     *      Object * old = this.set(0, new);
     *      if(old != nullptr)
     *          delete old;
     *      else
     *          delete new;
     *}</pre>
     *
     * @param index index(0-based)
     * @param value the new value
     */
    virtual ValueType set(const int index, const ValueType & value) = 0;

    /**
     * @return the iterator of array,  smart pointer to iterator object, free by myself
     */
    virtual std::shared_ptr<Iterator<ValueType>> iterator() const = 0;

    virtual void clear() = 0;

    bool operator == (const Array & right) const{
        return equals(right);
    }
    bool operator != (const Array & right) const {
        return !(*this == right);
    }
};


} // end of namespace object
} // end of namespace helper


#endif   /* HELPER_OBJECT_ARRAY_H */
